<?php
	/**
	  * @name		HTMLWrapper
	  * @brief		Clase con los metodos necesarios para generar etiquetas en HTML
	  * @author		Hermann D. Schimpf <hschimpf@gschimpf.com>
	  * @license	http://opensource.org/licenses/gpl-2.0.php GNU Public License
	  * @date		2010-05-19
	  * @version	0.1.0
  	**/

	abstract class HTMLWrapper extends MyDebuger implements MyVersions {
		/**
		  * @brief	Version de la clase
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @static
		  * @name	$version
		**/
		private static $version			= 0;
		/**
		  * @brief	Subversion de la clase
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @static
		  * @name	$subversion
		**/
		private static $subversion		= 1;
		/**
		  * @brief	Revision de la clase
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @static
		  * @name	$revision
		**/
		private static $revision		= 0;

		/**
		  * @brief	Tags HTML generados
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @name	$tags
		**/
		private $tags		= Array();
		/**
		  * @brief	Lista de Tags HTML validos
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @name	$validTags
		**/
		private $validTags= Array(
			'HTML',
				'HEAD',
					'TITLE', 'SCRIPT', 'STYLE', 'LINK',
				'BODY',
					'TABLE', 'TR', 'TD',
					'FORM', 'INPUT', 'BUTTON',
					'DIV', 'FONT', 'IMG'
		);

		/**
		  * @brief	Id de la instancia HTML
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @name	$myId
		**/
		private $myId		= False;

		/**
		  * @brief	Constructor de la clase
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	public
		  * @param	boolean	$debug Valor booleano para habilitar la depuracion de la clase
		  * @return	Void
		 **/
		public function __construct($debug = False, $name = __CLASS__, $tagType) {
			/* creamos el padre */
			parent::__construct($debug, $name);
			/* creamos el TAG HTML */
			$this->myId = $this->newHtml($tagType);
		}

		/**
		  * @brief	Destructor de la clase
		  * @date	2010-03-01
		  * @since	0.1.0
		  * @access	public
		  * @return	Void
		 **/
		public function __destruct() {
			/* matamos el padre */
			parent::__destruct();
		}

		/**
		  * @brief	Obtenemos la version de la clase
		  * @date	2010-03-01
		  * @since	0.1.0
		  * @access	public
		  * @static
		  * @return	String	Retornamos la version de la clase con el formato: v{version}.{subversion}.{revision}
		 **/
		public static function getVersion() {
			/* retornamos la version actual de la clase */
			return 'v' . self::$version . '.' . self::$subversion . '.' . self::$revision;
		}

		/**
		  * @brief	Metodo para retornar el contenido de la instancia
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @abstract
		  * @access	public
		  * @return	String	Contenido de la instancia
		 **/
		abstract public function getContent();

		/**
		  * @brief	Generamos un nuevo Tag HTML y retornamos el ID
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	String	Tag HTML a generar
		  * @return	Integer	ID del tag generado
		 **/
		protected final function newHtml($tagType, $autoClosed = False) {
			/* pasamos a mayusculas el TAG */
			$tagType = strtoupper($tagType);
			/* validamos que sea un HTML Tag valido */
			$this->validateTag($tagType);
			/* obtenemos el id para el tag */
			$tagId = $this->getNewTagId();
			/* almacenamos el tag */
			$this->tags[$tagId]['type'] = $tagType;
			/* asignamos un espacio para las propiedades */
			$this->tags[$tagId]['properties'] = Array();
			/* asignamos un espacio para el contenido */
			$this->tags[$tagId]['content'] = Array();
			/* asignamos si cierra automaticamente */
			$this->tags[$tagId]['autoClosed'] = $autoClosed;
			/* retornamos el id del tag */
			return $tagId;
		}

		/**
		  * @brief	Generamos una tabla y retornamos el ID
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID para el Tag
		  * @return	Integer	ID del tag Table
		 **/
		protected final function newTable($id = False) {
			/* retornamos la tabla */
			return $this->newObject('TABLE', $id);
		}

		/**
		  * @brief	Generamos un DIV y retornamos el ID
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID para el Tag
		  * @return	Integer	ID del tag DIV
		 **/
		protected final function newDIV($id = False) {
			/* retornamos el DIV */
			return $this->newObject('DIV', $id);
		}

		/**
		  * @brief	Generamos una fila TR y retornamos el ID
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID para el Tag
		  * @return	Integer	ID del tag TR
		 **/
		protected final function newTR($id = False) {
			/* retornamos el TR */
			return $this->newObject('TR', $id);
		}

		/**
		  * @brief	Generamos una fila TD y retornamos el ID
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID para el Tag
		  * @return	Integer	ID del tag TD
		 **/
		protected final function newTD($id = False) {
			/* retornamos la celda */
			return $this->newObject('TD', $id);
		}

		/**
		  * @brief	Agregamos contenido a un Tag HTML mediante su ID
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID del Tag a agregar contenido
		  * @param	Mixed		ID del Tag a agregar o Cadena a agregar
		  * @return	Void
		 **/
		protected final function addHtml($tagId, $idToAdd) {
			/* verificamos si el ID existe */
			$this->validateId($tagId);
			/* agregamos el Tag al especificado */
			$this->tags[$tagId]['content'][] = $idToAdd;
		}

		/**
		  * @brief	Seteamos una propiedad al Tag HTML
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID del Tag a especificar propiedad
		  * @param	String	Propiedad a asignar
		  * @param	String	Valor de la propiedad
		  * @return	Void
		 **/
		protected final function setProperty($tagId, $property, $value) {
			/* verificamos si el ID existe */
			$this->validateId($tagId);
			/* asignamos la propiedad al Tag especificado */
			$this->tags[$tagId]['properties'][$property] = $value;
		}

		/**
		  * @brief	Seteamos la propiedad class al Tag HTML
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID del Tag a especificar la propiedad class
		  * @param	String	Nombre de la clase
		  * @return	Void
		 **/
		protected final function setClass($tagId, $class) {
			/* asignamos la propiedad class al Tag */
			$this->setProperty($tagId, 'class', $class);
		}

		/**
		  * @brief	Seteamos la propiedad ID al Tag HTML
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID del Tag a especificar la propiedad ID
		  * @param	String	ID para el Tag
		  * @return	Void
		 **/
		protected final function setID($tagId, $id) {
			/* asignamos la propiedad id al Tag */
			$this->setProperty($tagId, 'id', $id);
		}

		/**
		  * @brief	Retornamos la cadena HTML de un Tag
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer	ID del Tag a obtener
		  * @return	String	Contenido del tag HTML
		 **/
		protected final function getHtml($tagId) {
			/* verificamos si el ID existe */
			$this->validateId($tagId);
			/* retornamos el contenido del tag */
			return $this->buildHtml($tagId);
		}

		/**
		  * @brief	Retornamos el ID local
		  * @date	2010-05-19
		  * @since	0.1.0
		  * @access	protected
		  * @return	Integer	ID del Tag local
		 **/
		protected final function getMyId() {
			/* retornamos el ID del tag local */
			return $this->myId;
		}

		/**
		  * @brief	Seteamos el ID local
		  * @date	2010-06-12
		  * @since	0.1.0
		  * @access	protected
		  * @param	Integer Nuevo ID local
		  * @return	Void
		 **/
		protected final function setMyId($newId) {
			/* retornamos el ID del tag local */
			$this->myId = $newId;
		}

		/**
		  * @brief	Generamos un elemento y retornamos el ID
		  * @date	2010-03-14
		  * @since	0.1.0
		  * @access	private
		  * @param	String	Tipo de Tag
		  * @param	Integer	ID para el Tag
		  * @return	Integer	ID del tag
		 **/
		private function newObject($tagType, $id) {
			/* creamos el elemento */
			$obj = $this->newHtml($tagType);
			/* verificamos si se asigno id */
			if ($id !== False)
				/* asignamos el id al div */
				$this->setID($obj, $id);
			/* retornamos el objeto */
			return $obj;
		}

		/**
		  * @brief	Retornamos un nuevo ID para un Tag HTML
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @return	Integer	ID para el nuevo Tag
		 **/
		private function getNewTagId() {
			/* retornamos la posicion maxima actual */
			return count($this->tags);
		}

		/**
		  * @brief	Verificamos si un ID existe
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @param	Integer	ID del Tag
		  * @return	Void
		 **/
		private function validateId($tagId) {
			/* verificamos si el ID existe */
			if (!array_key_exists($tagId, $this->tags))
				/* salimos con una excepcion */
				$this->newException('El ID ' . $this->bold($tagId) . ' no existe');
		}

		/**
		  * @brief	Verificamos si un Tag es valido
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @param	String	Tag HTML
		  * @return	Void
		 **/
		private function validateTag($tagType) {
			/* verificamos si el tag es valido */
			if (!in_array($tagType, $this->validTags))
				/* salimos con una excepcion */
				$this->newException('El tag ' . $this->bold($tagType) . ' no es valido');
		}

		/**
		  * @brief	Retornamos el contenido de un Tag
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @param	Integer	ID del tag
		  * @return	String	Contenido del Tag HTML
		 **/
		private function buildHtml($tagId) {
			/* iniciamos el TAG */
			$resultHtml = '<' . $this->tags[$tagId]['type'];
			/* Agregamos las propiedades del tag */
			$resultHtml .= $this->getTagProperties($tagId);
			/* verificamos si cierra automaticamente */
			if ($this->tags[$tagId]['autoClosed'] === True)
				/* cerramos el tag y retornamos */
				return $resultHtml .= '/>';
			/* cerramos el tag */
			$resultHtml .= '>';
			/* recorremos el contenido del tag */
			foreach ($this->tags[$tagId]['content'] AS $content)
				/* agregamos el contenido */
				$resultHtml .= (
					/* verificamos si es un ID de otro tag */
					gettype($content) == 'integer' ?
					/* armamos el contenido del Tag */
					$this->buildHtml($content) :
					/* cargamos el contenido */
					$content
				);
			/* finalizamos el tag */
			$resultHtml .= '</' . $this->tags[$tagId]['type'] . '>';
			/* retornamos la cadena */
			return $resultHtml;
		}

		/**
		  * @brief	Armamos las propiedades del tag y las retornamos como un string
		  * @date	2010-03-13
		  * @since	0.1.0
		  * @access	private
		  * @param	Integer	ID del tag
		  * @return	String	Propiedades del Tag
		 **/
		private function getTagProperties($tagId) {
			/* iniciamos una cadena de propiedades */
			$properties = '';
			/* recorremos las propiedades */
			foreach ($this->tags[$tagId]['properties'] AS $property => $value)
				/* agregamos la propuedad y su valor */
				$properties .= ' ' . strtolower($property) . '=\'' . $value . '\'';
			/* retornamos la cadena de propiedades */
			return $properties;
		}

		/**
		  * @brief	Capturamos las excepciones en la ejecucion del metodo invocado
		  * @date	2010-01-01
		  * @since	0.1.0
		  * @access	private
		  * @param	String	$method	Nombre del metodo a invocar
		  * @return	Mixed
		 **/
		private function catchExceptions($method = Null) {
			/* ingresamos a un control de errores para capturar mis excepciones */
			try {
				/* ingresamos a un control de errores para capturar las excepciones de ejecucion */
				try {
					/* realizamos algunas verificaciones */
					$this->verificarMetodo($method);
					/* obtenemos los parametros recibidos */
					$args = func_get_args();
					/* llamamos al metodo con los parametros */
					return call_user_func_array(Array(__CLASS__, $method), $this->buildArgs($args));
				/* capturamos las excepciones */
				} catch (Exception $e) {
					/* capturamos todos los errores y los transformamos en mi excepcion */
					$this->newException($e);
				}
			/* capturamos mis excepciones */
			} catch (MyException $e) {
				/* si se produjo una excepcion la manejamos con el metodo 'show' */
				$this->show($e->getMensaje());
				/* retornamos false */
				return False;
			}
		}
	}
?>